package au.edu.educationau.opensource.dsm.util;

//java stuff
import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.StringReader;
import java.io.StringWriter;
import java.io.Writer;
import java.net.URL;
import java.net.URLConnection;
import java.util.Enumeration;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.Map;
import java.util.Properties;

import javax.xml.transform.Source;
import javax.xml.transform.Templates;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.stream.StreamSource;

import org.apache.log4j.Logger;

import au.edu.educationau.opensource.dsm.cache.DiskCache;
import au.edu.educationau.opensource.dsm.service.PropertiesService;

public class SimpleTransform {

	static Logger logger = Logger.getLogger(SimpleTransform.class.getName());

	private static Hashtable stylesheets = new Hashtable();

	static {
		/*
		 * try {
		 * 
		 * String saxDriver =
		 * PropertiesService.getStringProperty("simpletransform.org.xml.sax.driver",
		 * "com.bluecast.xml.Piccolo"); String saxParser =
		 * PropertiesService.getStringProperty("simpletransform.javax.xml.parsers.SAXParserFactory",
		 * "com.bluecast.xml.JAXPSAXParserFactory"); String saxTranformer =
		 * PropertiesService.getStringProperty("simpletransform.javax.xml.transform.TransformerFactory",
		 * "org.apache.xalan.processor.TransformerFactoryImpl");
		 * System.setProperty( "org.xml.sax.driver", saxDriver );
		 * System.setProperty( "javax.xml.parsers.SAXParserFactory" ,
		 * saxParser);
		 * System.setProperty("javax.xml.transform.TransformerFactory",
		 * saxTranformer); } catch (Throwable t) { //be very cautious here. We
		 * are in class initialization. t.printStackTrace(); }
		 */
	}

	public static synchronized void destroy() {
		try {
			stylesheets.clear();
		} catch (Exception oe) {
		}
	}

	public static synchronized void prepareStylesheets() {

		logger.info("Loading stylesheets...");
		stylesheets.clear();
		/*
		 * try { String saxDriver =
		 * PropertiesService.getStringProperty("simpletransform.org.xml.sax.driver",
		 * "com.bluecast.xml.Piccolo"); String saxParser =
		 * PropertiesService.getStringProperty("simpletransform.javax.xml.parsers.SAXParserFactory",
		 * "com.bluecast.xml.JAXPSAXParserFactory"); String saxTranformer =
		 * PropertiesService.getStringProperty("simpletransform.javax.xml.transform.TransformerFactory",
		 * "org.apache.xalan.processor.TransformerFactoryImpl");
		 * System.setProperty( "org.xml.sax.driver", saxDriver );
		 * System.setProperty( "javax.xml.parsers.SAXParserFactory" ,
		 * saxParser);
		 * System.setProperty("javax.xml.transform.TransformerFactory",
		 * saxTranformer); } catch (Throwable t) { //be very cautious here. We
		 * are in class initialization. t.printStackTrace(); }
		 */
		if (logger.isDebugEnabled()) {
			logger.debug("Using org.xml.sax.driver = " + System.getProperty("org.xml.sax.driver"));
			logger.debug("Using javax.xml.parsers.SAXParserFactory = " + System.getProperty("javax.xml.parsers.SAXParserFactory"));
			logger.debug("Using javax.xml.transform.TransformerFactory = " + System.getProperty("javax.xml.transform.TransformerFactory"));
		}

		Source xsltSource;
		URL tmpURL = null;
		String xslPath = PropertiesService.getStringProperty("xml.stylesheets.classpath", "/xsl/");
		Properties xslProps = PropertiesService.getAllProperties("xsl");
		logger.debug("XSL Properties directory " + xslPath + ", xsl properties size " + xslProps.size());

		for (Enumeration e = xslProps.propertyNames(); e.hasMoreElements();) {
			String propertiesKey = (String) e.nextElement();
			String xslFileName = PropertiesService.getStringProperty("xsl." + propertiesKey, "");
			logger.debug("XSL Properties key xsl." + propertiesKey + ", xsl file name " + xslFileName);

			String xslFullFileName = xslPath + xslFileName;
			try {
				tmpURL = SimpleTransform.class.getResource(xslFullFileName);
			} catch (Exception exc) {
				logger.error("Error loading stylesheet! [" + xslFullFileName + "]", exc);
			}
			if (null == tmpURL) {
				logger.error("Stylesheet could not be loaded! [" + xslFullFileName + "]");
			} else {
				try {
					xsltSource = new StreamSource(tmpURL.toString());
					TransformerFactory transFact = TransformerFactory.newInstance();
					stylesheets.put(xslFileName, transFact.newTemplates(xsltSource));
					logger.debug("OK! Stylesheet [" + propertiesKey + "] " + tmpURL.toString());
				} catch (Throwable o) {
					logger.error("Error for stylesheet [" + tmpURL.toString() + "]", o);
				}
			}
		}

		logger.info("Found " + stylesheets.size() + " stylesheets and now preloaded for speed of sound response.");
	}

	public static String xalanTransform(String xml, String stylesheet_url, Map params) throws Exception {
		// default: cached output and managed
		return xalanTransform(stylesheet_url, xml, params, false, true, false, DiskCache.POLICY_UNIT_DAY);
	}

	public static String xalanTransform(String xml, String stylesheet_url) throws Exception {
		// default: cached output and managed with no parameters
		return xalanTransform(stylesheet_url, xml, null, false, true, false, DiskCache.POLICY_UNIT_DAY);
	}

	/**
	 * xalanTransform
	 * 
	 * @param url
	 * @param stylesheet_url
	 * @param params
	 * @param bypassCache
	 * @param managed
	 * @param flushCacheAfterTimeout
	 * @param itemRefreshPolicy
	 * 
	 * @return
	 * @throws Exception
	 */
	public static String xalanTransform(String stylesheet_url, String xml, Map params, boolean bypassCache, boolean managed, boolean flushCacheAfterTimeout, int itemRefreshPolicy) throws Exception {

		StreamSource xmlSource = null;
		StringWriter pw = new StringWriter();
		String key = PropertiesService.getStringProperty("xsl." + stylesheet_url, stylesheet_url);
		BufferedInputStream is = null;
		URLConnection conn = null;

		logger.debug("Performing transform for " + stylesheet_url + ", stored under key " + key + ". Bypass cache=" + bypassCache);

		StringReader asciiReader = new StringReader(xml);
		xmlSource = new StreamSource(asciiReader);

		Templates t = (Templates) stylesheets.get(key);

		if (null == t) {
			TransformerFactory transFact = TransformerFactory.newInstance();
			t = transFact.newTemplates(new StreamSource(stylesheet_url));
			stylesheets.put(key, t);
		} // if

		Transformer trans = t.newTransformer();
		trans.clearParameters();
		if (params != null) {
			Iterator keys = params.keySet().iterator();
			while (keys.hasNext()) {
				String name = (String) keys.next();
				String value = (String) params.get(name);
				trans.setParameter(name, new String(value));
			}
		} // if

		try {
			trans.transform(xmlSource, new StreamResult(pw));
		} catch (Throwable t1) {
			logger.error("Stylehseet Transform error was in XSL file: " + key, t1);
		} finally {
			try {
				pw.flush();
			} catch (Exception ex) {
			}
			try {
				pw.close();
			} catch (Exception ex) {
			}
			try {
				if (null != is)
					is.close();
			} catch (Exception ex) {
			}
			try {
				if (null != conn)
					conn.getInputStream().close();
			} catch (Exception ex) {
			}
			try {
				xmlSource.getInputStream().close();
			} catch (Exception ex) {
			}
		}

		return pw.toString();
	} // xalanTransform

	/**
	 * apiTransform
	 * 
	 * @param url
	 * @param stylesheet_url
	 * @param params
	 * @param bypassCache
	 * @param managed
	 * @param flushCacheAfterTimeout
	 * @param itemRefreshPolicy
	 * @param pw
	 * 
	 * @return
	 * @throws Exception
	 */
	public static boolean apiTransform(String url, String stylesheet_url, Map params, boolean bypassCache, boolean managed, boolean flushCacheAfterTimeout, int itemRefreshPolicy, Writer pw) throws Exception {
		StreamSource xmlSource;
		String key = stylesheet_url;

		URL byPassURL = new URL(url);
		URLConnection conn = byPassURL.openConnection();
		conn.connect();
		BufferedInputStream is = new BufferedInputStream(conn.getInputStream());
		BufferedReader asciiReader = new BufferedReader(new InputStreamReader(is, "ASCII"));
		xmlSource = new StreamSource(asciiReader);

		Templates t = (Templates) stylesheets.get(key);

		if (null == t) {
			TransformerFactory transFact = TransformerFactory.newInstance();
			t = transFact.newTemplates(new StreamSource(stylesheet_url));
			stylesheets.put(key, t);
		} // if

		Transformer trans = t.newTransformer();
		trans.clearParameters();
		if (params != null) {
			Iterator keys = params.keySet().iterator();
			while (keys.hasNext()) {
				String name = (String) keys.next();
				String value = (String) params.get(name);
				trans.setParameter(name, new String(value));
			}
		} // if

		trans.transform(xmlSource, new StreamResult(pw));

		try {
			xmlSource.getInputStream().close();
		} catch (Exception e) {
		}

		return true;

	} // apiTransform

	/**
	 * customTransform
	 * 
	 * @param data
	 * @param stylesheet_url
	 * @param params
	 * 
	 * @return transformed data
	 * @throws Exception
	 */
	public static String customTransform(String data, String stylesheet_url, Map params) throws Exception {
		StringWriter pw = new StringWriter();
		StreamSource xmlSource = new StreamSource(new StringReader(data));
		String key = stylesheet_url;

		Templates t = (Templates) stylesheets.get(key);

		if (null == t) {
			TransformerFactory transFact = TransformerFactory.newInstance();
			t = transFact.newTemplates(new StreamSource(stylesheet_url));
			stylesheets.put(key, t);
		} // if

		Transformer trans = t.newTransformer();
		trans.clearParameters();
		if (params != null) {
			Iterator keys = params.keySet().iterator();
			while (keys.hasNext()) {
				String name = (String) keys.next();
				String value = (String) params.get(name);
				trans.setParameter(name, new String(value));
			}
		} // if

		trans.transform(xmlSource, new StreamResult(pw));
		try {
			pw.flush();
			pw.close();
		} catch (IOException e) {
		}

		try {
			xmlSource.getInputStream().close();
		} catch (Exception e) {
		}

		return pw.toString();

	} // customTransform

} // SimpleTransform

// -- EOF
